package com.softcits.email.controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import com.softcits.email.common.FileComparator;
import com.softcits.email.common.FileInfoComparator;
import com.softcits.email.model.FileInfo;
import com.softcits.email.utils.ResultUtil;

@RestController
@RequestMapping("/file")
public class FileManagercontroller {
    private final static Logger LOGGER = LoggerFactory.getLogger(FileManagercontroller.class);
    String root = "d:"; 
    // d:study
    // d:\study
    private File rootDirectory = new File(root);
    
    {
        if(!rootDirectory.exists()) {
            rootDirectory.mkdirs();
        }
    }
    
    @PostMapping("/cf")
    public Object createFolder(String path, String folderName) {
        if(path != null) {
            path = path.replaceFirst("Root/", "");
            File directory = new File(rootDirectory, path + "/" + folderName);
            directory.mkdirs();
        } else {
            return ResultUtil.error("Current Directory missing....");
        }
        
        return ResultUtil.success();
    }
    
    public String[] getRoots() {
        String sRoots[] = null;
        File[] roots = File.listRoots();
        sRoots = new String[roots.length];
        for(int i = 0; i < roots.length; i++) {
            String fPath = roots[i].getPath();
            sRoots[i] = fPath;
        }
        
        return sRoots;
    }

    @GetMapping("/list")
    public Object listFiles(Integer start, Integer length, String path, String sRoot, HttpServletRequest req) {
        String searchValue = req.getParameter("search[value]");
        File[] files = null;
        File diretory = null;
        if(path != null && !"".equals(path)) {
            path = path.replaceFirst("Root/", "");
            diretory = new File(rootDirectory, "/" + path);
        } else {
            diretory = rootDirectory;
        }
        
        
        
        if(searchValue == null || "".equals(searchValue)) {
            files = diretory.listFiles();
        } else {
            files = diretory.listFiles(new FilenameFilter() {
                
                @Override
                public boolean accept(File dir, String name) {
                    return name.contains(searchValue);
                }
            });
        }

        List<FileInfo> list = new ArrayList<FileInfo>();
        int end = start + length;
        if(end > files.length) {
            end = files.length;
        }
        
        String sortDir = req.getParameter("order[0][dir]");
        String columnIndex = req.getParameter("order[0][column]");
        String columnName = req.getParameter(String.format("columns[%s][data]", columnIndex));
        Arrays.sort(files, new FileComparator(columnName, sortDir));

        for(int i = start; i < end; i++) {
            FileInfo finfo = new FileInfo();
            File f = files[i];
            String name = f.getName();
            
            finfo.setName(name);
            finfo.setPath(f.getPath());
            finfo.setFullPath(f.getAbsolutePath());
            int pos = 0;
            if( (pos = name.lastIndexOf(".")) != -1) {
                finfo.setExt(name.substring(pos + 1));
            }
            
            finfo.setContentType("");
            
            if(f.isDirectory()) {
                finfo.setSize(0l);
            } else {
                finfo.setSize(f.length());
            }
            
            
            finfo.setModificationTime(new Date(f.lastModified()));
            finfo.setCreationTime(new Date(f.lastModified()));
            String parent = f.getParent();
            parent = parent.replaceAll("\\\\", "/");
            LOGGER.debug("before: " + parent);
            String pathArr[] = parent.split(":");
            if(pathArr.length > 1) {
                if(pathArr[1].indexOf("\\") == 0) {
                    
                } else {
                    //parent = pathArr[0] + ":\\" + pathArr[1];
                }
            }
            
            parent = parent.replace(this.root, "Root");
            LOGGER.debug("after: " + parent);
            
            finfo.setParent(parent);
            list.add(finfo);
        }
        
        //Collections.sort(list, new FileInfoComparator(columnName, sortDir));
        return ResultUtil.success(list, Long.valueOf(files.length));
    }
    
    @PostMapping("/upload")
    public Object upload(MultipartFile file[], String path) throws IOException {
        
        if(path == null) {
            return ResultUtil.error("Current Directory Can not be null");
        }
        
        path = path.replaceFirst("Root/", "");
        File directory = new File(rootDirectory, path);
        
        if(null == file || file.length == 0) {
            return ResultUtil.error("Failed");
        }
        
        for(MultipartFile f: file) {
            InputStream is = f.getInputStream();
            File destFile = new File(directory, f.getOriginalFilename());
            if(!destFile.exists()) {
                FileOutputStream fos = new FileOutputStream(destFile);
                IOUtils.copy(is, fos);
                IOUtils.closeQuietly(fos);
            } else {
                return ResultUtil.error("File is existing...");
            }
        }
        
        return ResultUtil.success("Success");
    }
    
    @GetMapping("/download/{fileName}")
    public Object download(@PathVariable String fileName, String path, String dp, HttpServletRequest req, HttpServletResponse resp) throws IOException {
        if(null == fileName) {
            return ResultUtil.error("File Name is empty");
        }
        String fileName1 = req.getParameter("fileName");
        String path1 = req.getParameter("path");
        String dp1 = req.getParameter("dp");
        
        if(path == null) {
            return ResultUtil.error("Path is empty");
        }
        String contentType = req.getServletContext().getMimeType(fileName);

        path = path.replaceFirst("Root/", "");
        File directory = new File(rootDirectory, path);
        File file = new File(directory, fileName);
        if(dp == null) {
            dp = "attachment";
        }
        
        String range = req.getHeader("Range");
        int start = 0;
        if(range != null) {
            String[] rs = range.split("\\=");
            range = rs[1].split("\\-")[0];
            start = Integer.parseInt(range);
        }
       
        long length = file.length();
        if (start > 0)
        {
            resp.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
        }
        resp.addHeader("Accept-Ranges", "bytes");
        resp.addHeader("Content-Length", length + "");
        resp.addHeader("Content-Range", "bytes " + start + "-" + (length - 1) + "/" + length);

        resp.setHeader("content-disposition", dp +";filename="+URLEncoder.encode(fileName,"UTF-8"));
        LOGGER.debug("ContentType = " + contentType);
       
        if(fileName.toLowerCase().endsWith("html") || fileName.toLowerCase().endsWith("htm")) {
            resp.setContentType("text/plain");
        } else {
            resp.setContentType(contentType);
        }
        //resp.setHeader("Content-Type", contentType);
       //resp.setContentType("application/octet-stream");
        
        //resp.setContentType("application/pdf");
        
       // resp.setContentType("text/plain");
        FileInputStream fis = new FileInputStream(file);
        int initRead = (int) length / 5;
        fis.skip(start);
        OutputStream os = resp.getOutputStream();
        BufferedInputStream  bis = new BufferedInputStream(fis);
        byte[] unit = new byte[8096];
        BufferedOutputStream bos = new BufferedOutputStream(os);
        int content = 0;
        int totalRead = 0;
        while((content = bis.read(unit, 0, 8096)) != -1) {
            totalRead = totalRead + content;
            bos.write(unit, 0, content);
//            if(start == 0 && totalRead >= initRead) {
//                break;
//            }
            
        }

        IOUtils.closeQuietly(bis);
        os.flush();
        IOUtils.closeQuietly(bos);
        return null;
    }
}
